﻿using UnityEngine;
using System.Collections;

public class Character_Controller : MonoBehaviour {
	[HideInInspector]
	public Camera mainCam;		//main camera, and floorChecks object. FloorChecks are raycasted down from to check the player is grounded.
	[HideInInspector]
	public Character_Player character;
	private bool ignoreInput = true;
	private float prevX = 0f;
	private float prevY = 0f;
	
	float invulnerableCounter=0f;
	public float invulnerableTime;
	//the amount of time the player is invulnerable after being hit.

	Character_Health characterHealth;
	
	[HideInInspector]
	public bool controlActive;
	
	private Quaternion screenMovementSpace;
	private Vector3 screenMovementForward, screenMovementRight;

	public GameObject itemPingPrefab;

	[RPC]
	public void SetPlayer(NetworkPlayer player) {
		Debug.Log("SetPlayer.");
		
		if (player == Network.player) {
			Debug.Log("Owned a Player (id = " + player + ").");

			ignoreInput = false;

			mainCam = Camera.main;
			Camera_FollowCharacter camScript = mainCam.GetComponent<Camera_FollowCharacter> ();
			camScript.target = this.transform;
			camScript.enabled = true;
			camScript.SetUp ();
		}
	} // end RPC

	// Use this for initialization
	void Start () {
		character=GetComponent<Character_Player>();
		characterHealth=GetComponent<Character_Health>();
	}
	
	void Update () {
		if(character.Dead) { return; }
		UpdateControl();
		
		if(invulnerableCounter>0f){
			invulnerableCounter=Mathf.MoveTowards(invulnerableCounter,0f,Time.deltaTime);
			
			if(invulnerableCounter==0f){
				character.invulnerable=false;
			}
		}
	}
	
	void UpdateControl(){
		if (ignoreInput)
			return;

		float currX = Input.GetAxis ("Horizontal");
		float currY = Input.GetAxis ("Vertical");

		if (!(Mathf.Approximately (currX, prevX) && Mathf.Approximately(currY, prevY)))
			networkView.RPC ("SetSpeed", RPCMode.All, currX, currY);

		prevX = currX;
		prevY = currY;
		
		Vector3 destination=Vector3.zero;		
		
		if(Input.GetMouseButtonDown (0)){
			//character.SetRotAngle(destination);
			//character.SetRotTarget();
			
			character.attackPoint=destination;
			networkView.RPC ("RequestAttack", RPCMode.All);
		}

		if(Input.GetKeyDown("space"))
		{
			TransmitTinkerSignal ();
			ServerPrimary.instance.CreateGameObject(1, transform.position + 
			                                        new Vector3(0,0.5f,0), Quaternion.identity);
			GameObject.Instantiate(itemPingPrefab, ServerPrimary.instance.goalItem1Position, Quaternion.identity);
			GameObject.Instantiate(itemPingPrefab, ServerPrimary.instance.goalItem2Position, Quaternion.identity);
			GameObject.Instantiate(itemPingPrefab, ServerPrimary.instance.goalItem3Position, Quaternion.identity);
		}

		if (Input.GetKeyDown(KeyCode.L)) {
			this.TransmitLaughSignal();
		} 
	}

	[RPC]
	public void SetVelocityViaNetwork (Vector3 suddenSpeed)
	{
		Debug.Log ("SetVelocityViaNetwork: " + suddenSpeed);
		
		if (Network.isServer)
			networkView.RPC ("SetVelocityViaNetwork", RPCMode.Others, suddenSpeed);
		
		character.speed [0] = suddenSpeed;
	} // end RPC

	[RPC]
	void SetSpeed (float inputX, float inputY)	{
		if (0f != inputX || 0f != inputY) {
			Vector3 inputDir = new Vector3 (inputX, 0f, inputY).normalized;
			character.SetRotAngle (transform.position + inputDir);
			character.speed [1] = (character.dir * character.runSpeed);
		} else
			character.speed [1] = Vector3.zero;

		Debug.Log ("SetSpeed: " + character.speed[1]);
		
		character.SetRotTarget();

		if (character.anim)
			character.anim.SetFloat("Velocity", character.speed[1].magnitude);
	} // end RPC

	[RPC]
	void RequestAttack() {
		Debug.Log ("Request Attack.");
		if (Network.isServer)
			character.AttackStart();
	} // end RPC

	public void TransmitStabSignal ()
	{
		Debug.Log ("TransmitStabSignal.");
		networkView.RPC ("AnimateStab", RPCMode.All);
	} // end method

	public void TransmitTinkerSignal ()
	{
		networkView.RPC ("TinkeringAnim", RPCMode.All);
	}

	[RPC]
	public void AnimateStab() {
		Debug.Log ("AnimateStab.");
		StartCoroutine(character.characterMelee.HideKnife(2.5f));
		character.anim.Play("Stab", 1);
	} // end RPC

	[RPC]
	public void AnimateViaNetwork (string anim, int layer)
	{
		Debug.Log ("AnimateViaNetwork: " + anim + "," + layer);

		if (Network.isServer)
			networkView.RPC ("AnimateViaNetwork", RPCMode.Others, anim, layer);

		character.anim.Play (anim, layer);
	} // end RPC

	
	public bool StartInvulnerability(){
		bool invulnerableSuccess=false;
		
		if (invulnerableTime > 0f) {
			invulnerableCounter=invulnerableTime;
			invulnerableSuccess=true;
		}
		
		return invulnerableSuccess;
	}
	
	[RPC]
	public void TransmitLaughSignal ()
	{
		Debug.Log ("TransmitLaughSignal");

		if (Network.isServer)
			networkView.RPC ("TransmitLaughSignal", RPCMode.Others);
		
		character.Mouth.renderer.enabled = true;
		StartCoroutine(HideMouth(3.5f));
		character.anim.Play("ManiacalLaugh", 1);

		AudioSource aSource = this.GetComponent<AudioSource>();
		aSource.Play ();
		//SoundManager.PlaySFX(SoundManager.LoadFromGroup("Laugh1"));
	}

	[RPC]
	public void TinkeringAnim() {
		Debug.Log ("TinkeringAnim");
			character.Tablet.renderer.enabled = true;
			StartCoroutine(HideTablet(3.5f));
			character.anim.Play("TinkeringMove",1);
	}
	
	public void TinkeringStillAnim() {
			character.Tablet.renderer.enabled = true;
			StartCoroutine(HideTablet(3.5f));
			character.anim.Play("TinkeringStill",0);
			// In this case the second field is the layer, as we don't want the layer that affects only upper  torso, the layer is 0
	}
	
	IEnumerator HideMouth(float waitTime){
       yield return new WaitForSeconds(waitTime);
       character.Mouth.renderer.enabled = false;
    }
    
    IEnumerator HideTablet(float waitTime){
       yield return new WaitForSeconds(waitTime);
       character.Tablet.renderer.enabled = false;
    }

	public void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) {
		if (ServerPrimary.instance.CurrentState < ServerPrimary.GameState.MAPPING)
			return;

		if (stream.isWriting)
		{
			Vector3 pos = transform.position;
			stream.Serialize(ref pos);
		}
		else
		{
			Vector3 receivedPosition = Vector3.zero;
			stream.Serialize(ref receivedPosition);
			transform.position = receivedPosition;
		}
	} // end method
}
